PHP 7.0 changelog + casos de uso
Declaración de tipos primitivos, definición de tipo del retorno (coersitive/strict mode)
A las opciones para tipos de parámetros de entrada en funciones se suman nuevos a los ya existentes como clases, interfaces, arrays y callables (5.6), estos son string, int, float y bool.
<?php
function suma(float $a, float $b) :int {
return $a + $b
}
echo suma('2', 4);
// 6
Aquí es donde entra en juego el modo en este ejemplo el archivo corre en forma coercitiva, lo que nos permite pasar un valor string que es convertible o un int (los enteros son subconjunto de los float por lo que no hay drama) en lugar de un float al parámetro $a y que este nos resuelva la conversión de tipos on-the-fly (si es posible, como en este caso) y continuar la ejecución. De hecho en el ejemplo también sucede algo similar con el retorno, ya que se opera con dos float obteniendo otro float como resultado mientras se espera un int según la cabecera de la función, realizando la conversión inversa (a la del parametro de entrada $a ) al vuelo nuevamente.
<?php
// Coercitivo, el por defecto a menos que se indique lo contrario
// declare(strict_types=0);
// Estricto
declare(strict_types=1);
function suma(float $a, float $b) :int {
return (int)($a + $b)
}
echo suma(2.6, 4);
// 6.6
echo suma('2', 4.1);
// Lanza un TypeError, que implementa Throwable
Note: Throwable es la nueva interface implementada por Error y Exception, asociada al nuevo manejo/jerarquía de excepciones/errores recuperables/errores fatales en la versión 7.X . Queda como tópico para un post aparte !
Null coalescing operator/Operador de fusión de null
Debo admitir que este operador es uno de los que extrañaba de trabajar en C#. Operador que seguro vas a usar mucho, para escribir menos y dar mayor expresividad a tu código:
<?php
// El operador nos permite consultar si el elemento(1er operando) existe/no es nulo, en caso contrario retorna el 2do operando.
//PHP 5.6 - Ejemplo
$textoBusqueda = isset($_GET['texto']) ? $_GET['texto']: '';
// PHP 7.0 en adelante - Ejemplo
$textoBusqueda = $_GET['texto'] ?? '';
//También es posible encadenar su uso
$textoBusqueda = $_GET['texto1'] ?? $_GET['texto2'] ?? '';
Clases anónimas
Funcionalidad en principio no tan útil y que genera dudas, ¿por qué querría generar clases anónimas? Suena un poco a Code Smell.
Un primer acercamiento es la de generación de clases temporales para seguir atacando un problema principal y luego volver a donde se necesita una clase que se ajuste a una X interfaz, generando el archivo y codificando las particulares que requiera su implementación.
<?php
interface ILogger {
public function log(string $msg) :void ;
}
class Application {
private $logger;
public function logMessage(string $message): bool {
try {
$this->logger->log($message);
return true;
}
catch (Throwable $t) {
return false;
}
}
public function setLogger(ILogger $logger) { $this->logger = $logger; }
}
$app = new Application;
$app->setLogger(
new class implements ILogger {
public function log(string $msg) :void {
echo $msg;
}
}
);
$app->logMessage('Tracking process example');
// > Tracking process example
Por otro lado, es un aspecto muy útil al hacer testing cuando se quiere mockear ciertas clases para no depender de el uso de un framework de mocking en sí, o para surcir ocasiones particulares como moquear clases estáticas, donde ciertos frameworks no lo incluyen.
<?php
interface IQuerable {
public function query(string $query) :array;
}
class User {
public $id;
public $firstName;
public $lastName;
}
class UserRepository {
private $userTable = null;
public function __construct(IQuerable $userTable) :self {
$this->userTable = $userTable;
}
public function byId(int $userId) :?User {
$arrayOfUsers = $this->userTable->query('id = {$userId}');
return $arrayOfUsers ? $arrayOfUsers[0]: null;
}
}
class UserRepositoryTest extends SomeTestingFrameworkTestClass {
public function testPassWhenCallByIdGivenIdOfUserThatNotExistsReturnNull() :void {
$userTableMock = new class implements IQuerable {
public function query(string $query) :array { return []; }
};
$userThatNotExistsId = 0;
$userRepository = new UserRepository($userTableMock );
$userObtained = $userRepository->byId(userThatNotExistsId);
$this->assertNull($userObtained );
}
}
Filtros al deserealizar (unserialize)
La funcionalidad unserialize/serialize suele usarse para enviar objetos como mensajes entre sistemas o para almacenarlos para futuras utilizaciones, en casos prácticos como: colas de mensajes, ejecución de procesos asíncronos, etc.
Los filtros llegar para poder brindar mayor seguridad a la funcionalidad, para evitar fiarse al deserealizar objetos no esperados logrando evitar inyecciones, generando listas blancas de aquellos que si se consideraran.
<?php
class User {
public $id;
public $firstName;
public $lastName;
}
class Point {
public $x;
public $y;
}
// Funcionamiento que ya se tenia en la version 5.6
// Comportamiento predeterminado (lo mismo que omitir el segundo argumento) que acepta todas las clases
$object = unserialize($stringObject, ['allowed_classes' => true]) = unserialize($stringObject);
// Aplicación de filtros a los tipos-clases a utilizar
// Convierte unicamente de string -> bjetos de tipo User|Point
// El resto de objetos serializados como string que se les pase seran convertidos todos a un objeto __PHP_Incomplete_Class
$data = unserialize($foo, ['allowed_classes' => [User::class, 'Point']]);
// Todos los objetos seran convertidos a un objeto __PHP_Incomplete_Class
$data = unserialize($foo, ['allowed_classes' => false]);
USE en grupos
Incluir clases que compartan namespace, con solo un nivel de anidamiento.
<?php
// Código en PHP 5.6
use un\espacioDeNombres\ClaseA;
use un\espacioDeNombres\ClaseB;
use un\espacioDeNombres\ClaseC as C;
use function un\espacioDeNombres\fn_a;
use function un\espacioDeNombres\fn_b;
use function un\espacioDeNombres\fn_c;
use const un\espacioDeNombres\ConstA;
use const un\espacioDeNombres\ConstB;
use const un\espacioDeNombres\ConstC;
// Código desde PHP 7.0+
use un\espacioDeNombres\{ClaseA, ClaseB, ClaseC as C};
use function un\espacioDeNombres\{fn_a, fn_b, fn_c};
use const un\espacioDeNombres\{ConstA, ConstB, ConstC};
(Caso de ejemplo extraido de la documentación de PHP)
OTROS: Casos que no me parecen tan comunes de ser utilizados, o bien, lo suficientemente simples como la el operador división entera, que se introdujeron en está versión:
- Operador nave espacial (Spaceship operator)
- Constantes de tipo arrays utilizando define()
- Unicode codepoint escape syntax
- Closure::call()
- IntlChar
- Expectations (leer con atención, no dice Exceptions)
- Generator Return Expressions
- Generator delegation
- Divisi'on entera intdiv()
- Session options (pasaje de parámetros en el session_start para configurar cuestiones de la misma)
- pregreplacecallback_array()
- CSPRNG Functions